﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using XXF.BaseService.ServiceCenter.Service.OpenDoc;
using XXF.BaseService.ServiceCenter.SystemRuntime;

namespace XXF.BaseService.ServiceCenter.Service.Protocol
{
    /// <summary>
    /// 用于自定义协议相关转换及自身协议解析提供类
    /// 如:转thrift协议
    /// </summary>
    public class ProtocolProvider
    {
        public ProtocolProvider() { }

        /// <summary>
        /// 将类型转换为服务协议
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public ServiceProtocal From(Type type)
        {

            ServiceProtocal r = new ServiceProtocal(); r.MethodProtocols = new List<MethodProtocol>(); r.EntityProtocals = new List<EntityProtocal>();
            var attr1 = GetCustomAttribute<ServiceDocAttribute>(type);
            if (attr1 != null)
            {
                r.ServiceDoc = attr1;
                r.Name = type.Name;
                //公开服务方法解析
                foreach (var m in GetOpenMethods(type))
                {
                    MethodProtocol t = new MethodProtocol();
                    t.InputParams = GetInputParamsProtocalsOfMethod(m.Key);
                    t.MethodDoc = m.Value;
                    t.Name = m.Key.Name;
                    t.ReturnParam = GetReturnParamProtocalOfMethod(m.Key);
                    r.MethodProtocols.Add(t);
                }
                //自定义实体类型解析
                var customtypes = GetCustomTypeInMethodProtocols(r.MethodProtocols);
                foreach (var c in customtypes)
                {
                    var attr = GetCustomAttribute<EntityDocAttribute>(c);
                    EntityProtocal t = new EntityProtocal();
                    t.EntityDoc = attr;
                    t.Name = c.Name;
                    t.PropertyDocs = GetPropertyDocs(c);
                    t.PropertyParams = GetPropertyParams(c);
                    r.EntityProtocals.Add(t);
                }
            }
            return r;
        }

        public string ToThrift(ServiceProtocal protocal, string namespacename)
        {
            ProtocolsToThrift t = new ProtocolsToThrift();
            return t.To(protocal, namespacename);
        }
        /// <summary>
        /// 获取服务开放的方法
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private Dictionary<MethodInfo, MethodDocAttribute> GetOpenMethods(Type type)
        {
            Dictionary<MethodInfo, MethodDocAttribute> rs = new Dictionary<MethodInfo, MethodDocAttribute>();
            foreach (var m in type.GetMethods())
            {
                var attr = GetCustomAttribute<MethodDocAttribute>(m);
                if (attr != null)
                    rs.Add(m, attr);
            }
            return rs;
        }
        /// <summary>
        /// 获取开放方法的输入参数协议
        /// </summary>
        /// <param name="mehtodinfo"></param>
        /// <returns></returns>
        private List<ParamProtocal> GetInputParamsProtocalsOfMethod(MethodInfo mehtodinfo)
        {
            List<ParamProtocal> rs = new List<ParamProtocal>();

            foreach (var p in mehtodinfo.GetParameters())
            {
                var attr = GetCustomAttribute<EntityDocAttribute>(p.ParameterType);
                ParamProtocal t = new ParamProtocal();
                t.IsCustomType = ((attr != null) ? true : false);
                t.Name = p.Name;
                t.TypeName = GetTypeName(p.ParameterType);
                t.SourceType = p.ParameterType;
                rs.Add(t);
            }
            return rs;
        }
        /// <summary>
        /// 获取开放方法的返回参数协议
        /// </summary>
        /// <param name="mehtodinfo"></param>
        /// <returns></returns>
        private ParamProtocal GetReturnParamProtocalOfMethod(MethodInfo mehtodinfo)
        {
            bool IsCustomType = false;
            var attr = GetCustomAttribute<EntityDocAttribute>(mehtodinfo.ReturnType);

            ///List数组处理
            if (mehtodinfo.ReturnType.IsGenericType && mehtodinfo.ReturnType.GetGenericTypeDefinition() == typeof(List<>))
            {
                IsCustomType = GetCustomAttribute<EntityDocAttribute>(mehtodinfo.ReturnType.GetGenericArguments()[0]) != null || IsCustomType;
            }
            ///dictionary数组处理
            else if (mehtodinfo.ReturnType.IsGenericType && mehtodinfo.ReturnType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
            {
                IsCustomType = GetCustomAttribute<EntityDocAttribute>(mehtodinfo.ReturnType.GetGenericArguments()[0]) != null || IsCustomType;
                IsCustomType = GetCustomAttribute<EntityDocAttribute>(mehtodinfo.ReturnType.GetGenericArguments()[2]) != null || IsCustomType;
            }
            else
            {
                IsCustomType = GetCustomAttribute<EntityDocAttribute>(mehtodinfo.ReturnType) != null || IsCustomType;

            }
            ParamProtocal r = new ParamProtocal();
            r.IsCustomType = IsCustomType;
            r.Name = mehtodinfo.ReturnParameter.ParameterType.Name;
            r.TypeName = GetTypeName(mehtodinfo.ReturnParameter.ParameterType);
            r.SourceType = mehtodinfo.ReturnParameter.ParameterType;
            return r;
        }
        /// <summary>
        /// 获取所有开放方法涉及到的自定义类型
        /// </summary>
        /// <param name="methodprotocols"></param>
        /// <returns></returns>
        private List<Type> GetCustomTypeInMethodProtocols(List<MethodProtocol> methodprotocols)
        {
            List<Type> rs = new List<Type>();
            foreach (var mp in methodprotocols)
            {
                foreach (var p in mp.InputParams)
                {
                    if (p.IsCustomType && !rs.Contains(p.SourceType))
                    {
                        if (!p.SourceType.IsGenericTypeDefinition)// && p.SourceType.GetGenericTypeDefinition() != typeof(Dictionary<,>) && p.SourceType.GetGenericTypeDefinition() != typeof(List<>) && !rs.Contains(p.SourceType))
                        {
                            rs.Add(p.SourceType);
                        }
                        GetCustomTypeInType(p.SourceType, rs);//递归搜索该类型下面的所有类型
                    }
                }
                if (mp.ReturnParam.IsCustomType && !rs.Contains(mp.ReturnParam.SourceType))
                {
                    if (!mp.ReturnParam.SourceType.IsGenericTypeDefinition)// && mp.ReturnParam.SourceType.GetGenericTypeDefinition() != typeof(Dictionary<,>) && mp.ReturnParam.SourceType.GetGenericTypeDefinition() != typeof(List<>))
                    {
                        rs.Add(mp.ReturnParam.SourceType);
                    }
                    GetCustomTypeInType(mp.ReturnParam.SourceType, rs);//递归搜索该类型下面的所有类型
                }
            }
            return rs;
        }

        /// <summary>
        /// 递归搜索所有自定义类型
        /// </summary>
        /// <param name="type"></param>
        /// <param name="customtypes"></param>
        /// <returns></returns>
        private List<Type> GetCustomTypeInType(Type type, List<Type> customtypes)
        {

            ///List数组处理
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
            {
                Type itemType = type.GetGenericArguments()[0];
                if (!customtypes.Contains(itemType))
                {
                    if (null != GetCustomAttribute<EntityDocAttribute>(itemType) && !customtypes.Contains(itemType))
                    {
                        customtypes.Add(itemType);
                        GetCustomTypeInType(itemType, customtypes);
                    }
                }
            }

            ///dictionary数组处理
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
            {
                Type[] itemType = type.GetGenericArguments();
                if (null != GetCustomAttribute<EntityDocAttribute>(itemType[0]) && !customtypes.Contains(itemType[0]))
                {
                    customtypes.Add(itemType[0]);
                    GetCustomTypeInType(itemType[0], customtypes);
                }
                if (null != GetCustomAttribute<EntityDocAttribute>(itemType[1]) && !customtypes.Contains(itemType[1]))
                {
                    customtypes.Add(itemType[1]);
                    GetCustomTypeInType(itemType[1], customtypes);
                }
            }

            foreach (var p in type.GetProperties())
            {
                var attr = GetCustomAttribute<PropertyDocAttribute>(p);
                ///List数组处理
                if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                {
                    Type itemType = p.PropertyType.GetGenericArguments()[0];
                    if (null != GetCustomAttribute<EntityDocAttribute>(itemType) && !customtypes.Contains(itemType))
                    {
                        customtypes.Add(itemType);
                        GetCustomTypeInType(itemType, customtypes);
                    }
                }

                ///dictionary数组处理
                if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
                {
                    Type[] itemType = p.PropertyType.GetGenericArguments();
                    if (null != GetCustomAttribute<EntityDocAttribute>(itemType[0]) && !customtypes.Contains(itemType[0]))
                    {
                        customtypes.Add(itemType[0]);
                        GetCustomTypeInType(itemType[0], customtypes);
                    }
                    if (null != GetCustomAttribute<EntityDocAttribute>(itemType[1]) && !customtypes.Contains(itemType[1]))
                    {
                        customtypes.Add(itemType[1]);
                        GetCustomTypeInType(itemType[1], customtypes);
                    }
                }
                if (attr == null)
                {
                    continue;
                }

                var pattr = GetCustomAttribute<EntityDocAttribute>(p.PropertyType);
                if (pattr == null || customtypes.Contains(p.PropertyType))
                    continue;
                customtypes.Add(p.PropertyType);
                GetCustomTypeInType(p.PropertyType, customtypes);
            }
            return customtypes;
        }
        /// <summary>
        /// 获取自定义类型的属性文档
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private List<PropertyDocAttribute> GetPropertyDocs(Type type)
        {
            List<PropertyDocAttribute> rs = new List<PropertyDocAttribute>();
            foreach (var p in type.GetProperties())
            {
                var attr = GetCustomAttribute<PropertyDocAttribute>(p);
                if (attr != null)
                {
                    rs.Add(attr);
                }
            }
            return rs;
        }
        /// <summary>
        /// 获取自定义类型的属性协议
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private List<ParamProtocal> GetPropertyParams(Type type)
        {
            List<ParamProtocal> rs = new List<ParamProtocal>();
            foreach (var p in type.GetProperties())
            {
                var attr = GetCustomAttribute<PropertyDocAttribute>(p);
                if (attr != null)
                {
                    var attr2 = GetCustomAttribute<EntityDocAttribute>(p.PropertyType);
                    ParamProtocal t = new ParamProtocal();
                    t.IsCustomType = (attr2 != null ? true : false);
                    t.Name = p.Name;
                    t.SourceType = p.PropertyType;
                    t.TypeName = GetTypeName(p.PropertyType);
                    rs.Add(t);
                }
            }
            return rs;
        }

        private T GetCustomAttribute<T>(Type type) where T : OpenDocAttribute
        {
            var atts = type.GetCustomAttributes(typeof(T), true);
            if (atts != null && atts.Length > 0)
            {
                return atts[atts.Length - 1] as T;
            }
            else
                return default(T);
        }

        private T GetCustomAttribute<T>(ICustomAttributeProvider info) where T : OpenDocAttribute
        {
            var atts = info.GetCustomAttributes(typeof(T), true);
            if (atts != null && atts.Length > 0)
            {
                return atts[atts.Length - 1] as T;
            }
            else
                return default(T);
        }

        //自定义协议不支持类型
        readonly List<Type> notsupporttypes = new List<Type>() { typeof(System.SByte), typeof(System.Char), typeof(System.Decimal) 
       , typeof(System.Single), typeof(System.UInt32), typeof(System.UInt64), typeof(System.UInt16),typeof(System.Array)};
        //自定义协议支持基本类型
        readonly Dictionary<Type, string> supporttypes = new Dictionary<Type, string>() { { typeof(System.Boolean), "bool" }, { typeof(System.Byte), "byte" },
       { typeof(System.Int16), "short" },{ typeof(System.Int32), "int" },{ typeof(System.Int64), "long" },{ typeof(System.Double), "double" },{ typeof(System.String), "string" },
       { typeof(void), "void" },
       };
        //自定义协议支持类型描述
        readonly string supporttypesdescription = "bool;byte;int;int16;long;double;string;byte[];List<>;Dictionary<,>;void;class;";
        /// <summary>
        /// 类型解析
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private string GetTypeName(Type type)
        {
            if (type.IsGenericType)
            {
                if (type.GetGenericTypeDefinition() == typeof(List<>))
                {
                    return string.Format("List<{0}>", GetTypeName(type.GetGenericArguments()[0]));
                }
                else if (type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
                {
                    return string.Format("Dictionary<{0},{1}>", GetTypeName(type.GetGenericArguments()[0]), GetTypeName(type.GetGenericArguments()[1]));
                }
                throw new ServiceCenterException(string.Format("协议对{0}类型不支持,协议只支持【{1}】", type.Name, supporttypesdescription));//排除其他泛型
            }
            //字节流（特殊）
            if (type == typeof(byte[]) || type == typeof(Byte[]))
                return "byte[]";
            /*支持的协议特殊转换*/
            if (supporttypes.ContainsKey(type))
                return supporttypes[type];

            /*不支持的协议检查*/
            if (notsupporttypes.Contains(type) || (type == typeof(System.Array) || type.BaseType == typeof(System.Array)))//排除数组和其他类型
                throw new ServiceCenterException(string.Format("协议对{0}类型不支持,协议只支持【{1}】", type.Name, supporttypesdescription));

            return type.Name;
        }
    }
}
